`include "cpu_def.vh"

module div(
  input div_clk,
  input rst,
  input div,
  input div_signed,
  input [31:0] x,
  input [31:0] y,

  output [31:0] s,
  output [31:0] r,
  output        complete
);

  wire [31:0] x_neg = ~x + 1;
  wire [32:0] x_abs = (div_signed && x[31]) ? {1'b0, x_neg} : {1'b0, x};

  wire [32:0] x_init = x_abs;
  wire [32:0] y_init = (div_signed && y[31]) ? {1'b1, y} : (~y + 1);

  wire        start;
  wire [32:0] adder_result;
  wire        diff_sign;
  wire [32:0] remainder_next;
  wire [31:0] s_abs;
  wire [31:0] r_abs;

  reg [ 5:0] count;
  reg        diff_sign_r;
  reg        dividend_sign_r;
  reg [32:0] remainder;
  reg [32:0] dividend;
  reg [32:0] divisor;

  assign start = count == 6'd0;
  assign complete = count == 6'd33;
  assign adder_result = remainder + divisor;
  assign diff_sign = adder_result[32] ^ remainder[32];
  assign remainder_next = diff_sign ? remainder[32:0] : adder_result[32:0];

  always@(posedge div_clk) begin
    if (start) begin
      diff_sign_r <= (x[31] ^ y[31]) & div_signed;
      dividend_sign_r <= x[31] & div_signed;
    end
  end

  always@(posedge div_clk) begin
    if (rst || complete || ~div) begin
      count <= 6'd0;
    end else begin
      count <= count + 6'd1;
    end
  end

  always@(posedge div_clk) begin
    if (start) begin
      remainder <= {32'd0, x_init[32]};
    end else begin
      remainder[32:1] <= remainder_next[31:0];
      remainder[0] <= dividend[32];
    end
  end

  always@(posedge div_clk) begin
    if (start) begin
      dividend <= {x_init[31:0], 1'b0};
    end else begin
      dividend[32:1] <= dividend[31:0];
      dividend[0] <= ~diff_sign;
    end
  end

  always@(posedge div_clk) begin
    if (start) begin
      divisor <= y_init;
    end
  end

  assign s_abs = {dividend[30:0], ~diff_sign};
  assign r_abs = remainder_next;
  assign s = diff_sign_r ?  ~s_abs + 1 : s_abs;
  assign r = dividend_sign_r ? ~r_abs + 1 : r_abs;

endmodule
